from time import sleep
import pathlib
import re
from .log import logger, snapshot_post
from .globals import g, now, timestamp
from .elements import e
from .windows import w
from .snapshot import Snapshot
from .keywords import web, common, database, interface, ios, android
from .utility import replace_dict, replace
from .keywords.codeapi import Element, web_driver, testdata, run_snippet
from records import Database
# import sys
#
# sys.setrecursionlimit(10000)


def elements_format(page: str, element: str):
    if not page:
        page = g.current_page

    if not element:
        return page, '', element

    if page in ('SNIPPET', '用例片段') or element in ('变量赋值',):
        return page, '', element

    elements = [element]  # .split('|')
    if len(elements) == 1:
        custom, el = e.have(page, element)
        g.current_page = page
        return page, custom, el
    else:
        els = []
        for _element in elements:
            custom, el = e.have(page, _element.strip())
            els.append(el)
        g.current_page = page
        return page, custom, els


def v_data(d):
    data = ''
    for k, v in d.items():
        data += k + '=' + str(v) + ','
    return data[:-1]


def test_v_data():
    data = {'a': 1, 'b': 'b'}
    v_data(data)


class TestCase:
    def __init__(self, testcase):
        self.testcase = testcase
        self.snippet_steps = {}

    def run(self):
        case_type = self.testcase['condition']
        logger.info(
            f"run {case_type + ' '}testCase[id:{self.testcase['id']},编号:{self.testcase['case_num']}]"
            f": {self.testcase['title']}"
        )
        self.testcase['result'] = 'success'
        self.testcase['report'] = ''
        if_result = ''

        for step in self.testcase['steps']:
            # 统计开始时间
            step['start_timestamp'] = timestamp()
            g.platform = step['platformName']
            step_type = step.get('type')
            if not step_type:
                # step_type = 'snippet'
                raise Exception('当前步骤类型为空！')
            if self.testcase.get('result_case_id'):
                g.result_case_id = self.testcase['result_case_id']
            step['result_case_id'] = g.result_case_id

            # if 为否，不执行 then 语句
            if (step['control'] == '>' or step['control'] == 'then') and not if_result:
                step['score'] = '-'
                step['end_timestamp'] = timestamp()
                continue

            # if 为真，不执行 else 语句
            if (step['control'] == '<' or step['control'] == 'else') and if_result:
                step['score'] = '-'
                step['end_timestamp'] = timestamp()
                continue

            # logger.info(f"run step {step['no']}: {step['step_name']}")
            logger.info(
                f"run {case_type + ' '}testCase {self.testcase['title']}[id:{self.testcase['id']}]"
                f"::step {step['no']}->{step['step_name']}"
            )

            label = f"{g.task_id}.{self.testcase['id']}#{str(step['no'])}"
            snap = Snapshot()
            try:
                after_function = step['data'].pop('AFTER_FUNCTION', '')

                # 变量替换
                replace_dict(step['data'])
                g.var.update(step['data'])
                replace_dict(step['expected'])
                s_data = []
                if step['data']:
                    s_data.append('测试数据：' + str(step['data']))
                if step['output']:
                    s_data.append('输出数据：' + str(step['output']))
                if step['expected']:
                    s_data.append('预期结果：' + str(step['expected']))
                if s_data:
                    logger.info('，'.join(s_data))

                t = step['data'].get('步骤执行前等待(秒)')
                if t:
                    sleep(float(t))

                step['data'].pop('BEFORE_FUNCTION', '')

                if isinstance(step['element'], str):
                    step['element'] = replace(step['element'])
                    step['_element'] = step['element']
                elif isinstance(step['element'], list):
                    for i in range(len(step['element'])):
                        step['element'][i] = replace(step['element'][i])
                    step['_element'] = '|'.join(step['element'])

                step['vdata'] = v_data(step['data'])

                if step_type == 'web_ui':
                    # 处理截图数据
                    snap.pre(step, label)

                    if step['keyword'] not in ('alert_box',):
                        ele = e.get(step['element'])
                        if ele:
                            w.switch_frame(ele[0])

                    # 调用关键字实现
                    try:
                        func = getattr(web, step['keyword'].lower())
                    except AttributeError:
                        raise Exception(f"无此关键字:{step['keyword']}，请重新配置当前步骤的关键字！")
                    func(step)
                elif step_type == 'android':
                    # 调用关键字实现
                    try:
                        func = getattr(android, step['keyword'].lower())
                    except AttributeError:
                        raise Exception(f"无此关键字:{step['keyword']}，请重新配置当前步骤的关键字！")
                    func(step)

                elif step_type == 'ios':
                    # 调用关键字实现
                    try:
                        func = getattr(ios, step['keyword'].lower())
                    except AttributeError:
                        raise Exception(f"无此关键字:{step['keyword']}，请重新配置当前步骤的关键字！")
                    func(step)
                elif step_type == 'database':
                    try:
                        func = getattr(database, step['keyword'].lower())
                    except AttributeError:
                        raise Exception(f"无此关键字:{step['keyword']}，请重新配置当前步骤的关键字！")
                    func(step)
                elif step_type == 'interface':
                    try:
                        func = getattr(interface, step['keyword'].lower())
                    except AttributeError:
                        raise Exception(f"无此关键字:{step['keyword']}，请重新配置当前步骤的关键字！")
                    func(step)

                elif step_type == 'snippet':
                    result = getattr(
                        common, step['keyword'].lower())(step)
                    self.testcase['result'] = result
                    if result != 'success':
                        step['end_timestamp'] = timestamp()
                        break
                elif step_type == 'function':
                    getattr(common, step['keyword'].lower())(step)
                elif step_type == 'code':
                    # 测试数据相关:
                    #   引用：testdata.get('测试数据名称', default)，testdata['测试数据名称']
                    #   赋值：testdata.set(key, value), testdata.update(dict)
                    # driver引用: web_driver
                    # 执行用例片段: run_snippet('用例片段ID', setting)
                    # setting默认为: {"executeCount":"1","exitCondition":"成功","errorStillRun":"false"}
                    # 引用元素对象: element('element_id')，例：element('1321').click()、element('1321').by_value
                    # 数据库相关:
                    # 日志对象：logger，logger.info(''), logger.warning('')
                    code = step['code']
                    _source = compile(
                        code,
                        f'code_case-{self.testcase["title"]}[{self.testcase["id"]}]'
                        f'.step-{step["step_name"]}[{step["step_id"]}]',
                        'exec'
                    )
                    exec(_source)
                else:
                    raise Exception(f'无此关键字类型：{step_type}')

                step['score'] = 'OK'
                t = step['data'].get('步骤执行后等待(秒)')
                if t:
                    sleep(float(t))

                # if 语句结果赋值
                if step['control'] == '^' or step['control'] == 'if':
                    if_result = True

                if after_function:
                    replace_dict({'after_function': after_function})
                # 操作后，等待0.2秒
                # sleep(0.2)
            except Exception as exception:
                file_name = f"{g.task_id}_{g.result_case_id}_{str(timestamp())}.png"
                step['snapshot'] = str(pathlib.Path(snap.snapshot_folder, file_name))
                try:
                    if w.frame != 0:
                        g.driver.switch_to.default_content()
                        w.frame = 0
                    try:
                        g.driver.get_screenshot_as_file(step['snapshot'])
                    except:
                        logger.exception('截图失败！')
                except:
                    logger.exception(
                        '*** save the screenshot is failure ***')
                logger.exception(str(exception))
                step['score'] = 'NO'
                # ------- 上传报错时截图 -------
                snapshot_file = step.get('snapshot')
                if snapshot_file:
                    snapshot_post(snapshot_file, file_name='报错时截图', file_name_post=file_name)

                # if 语句结果赋值
                if step['control'] == '^' or step['control'] == 'if':
                    if_result = False
                    step['end_timestamp'] = timestamp()
                    continue
                # if 语句结果赋值- if not
                elif step['control'] == 'if not':
                    if_result = True
                    step['end_timestamp'] = timestamp()
                    continue

                self.testcase['result'] = 'failure'
                self.testcase['report'] = 'step-%s|%s|%s: %s' % (
                    step['no'], step['keyword'], step['element'], exception)
                step['remark'] += str(exception)
                step['end_timestamp'] = timestamp()
                break

            # 统计结束时间
            step['end_timestamp'] = timestamp()

            if g.task_data['stop_task']:
                logger.info('任务已被终止！')
                raise Exception('任务已被终止！')

        logger.info(
            f"{case_type + ' '}case {self.testcase['title']}[id:{self.testcase['id']},"
            f"编号:{self.testcase['case_num']}] end. result: {self.testcase['result']}"
        )

